package com.spring.sso.config.security.manage;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.spring.sso.common.CommonResult;
import com.spring.sso.common.Constant;
import com.spring.sso.common.DefaultUserDetails;
import com.spring.sso.config.AuthenticationConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.Map;

/**
 * @author : pangfuzhong
 * @description
 * @date : 2021/9/21 15:02
 */
@Slf4j
public class SsoAuthenticationManager implements AuthenticationManager {
    private AuthenticationConfig authenticationConfig;
    public SsoAuthenticationManager(AuthenticationConfig authenticationConfig) {
        this.authenticationConfig = authenticationConfig;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
        log.info("--> 当前待接入认证中心认证内容为: userName = {}, password ={}", auth.getPrincipal(), auth.getCredentials());
        if(StringUtils.isBlank(auth.getPrincipal().toString()) || StringUtils.isBlank(auth.getCredentials().toString())) {
            throw new BadCredentialsException("username or password is not empty");
        }

        // 1、远程认证
        RestTemplate restTemplate = this.authenticationConfig.getRestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.put(Constant.USERNAME, Lists.newArrayList(auth.getPrincipal().toString()));
        params.put(Constant.PASSWORD, Lists.newArrayList(auth.getCredentials().toString()));
        params.put(Constant.APPNAME, Lists.newArrayList(this.authenticationConfig.getAppName()));
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
        // --> 请求认证中心 POST /sso/channel/login/auth 地址进行认证, 该地址认证中心不拦截
        ResponseEntity<CommonResult> responseEntity = restTemplate.exchange(this.authenticationConfig.getServerLoginAuthUrl(), HttpMethod.POST, requestEntity, CommonResult.class);
        CommonResult commonResult = responseEntity.getBody();
        DefaultUserDetails userDetails = JSONObject.parseObject((JSON.toJSONString(JSONObject.parseObject(JSON.toJSONString(commonResult.getData())))), DefaultUserDetails.class);
        // 2、封装token信息
        auth.setDetails(userDetails);
        return auth;
    }
}
